home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Peter Lewis / PNL Libraries / OOStaticEdit.p < prev    next >
Encoding:
Text File  |  1994-08-27  |  13.4 KB  |  504 lines  |  [TEXT/PJMM]

  1. unit OOStaticEdit;
  2.  
  3. interface
  4.  
  5.     type
  6.         TEStaticObject = object
  7.                 window: dialogPtr;
  8.                 titem: integer;
  9.                 vcontrol, hcontrol: controlHandle;
  10.                 te: TEHandle;
  11.                 titemr: rect;
  12.                 hasgrow, drawgrow: boolean; { hasgrow -> leave room for grow icon, drawgrow -> draw it during updates }
  13.                 doubleClickTime, tripleClickTime: longInt;
  14.                 procedure Create (dlg: dialogPtr; item, width: integer; vscroll, hscroll, hasgrowb, drawgrowb: boolean);
  15.                 procedure Destroy;
  16.                 procedure Adjust;
  17.                 procedure Resize;
  18.                 procedure Draw;
  19.                 function EditMenuEnabled: boolean;
  20.                 procedure SetEditMenuItem (item: integer);
  21.                 procedure DoEditMenu (item: integer);
  22.                 procedure DoItemWhere (er: eventRecord; item: integer);
  23.                 procedure DoIdle;
  24.                 procedure DoKey (modifiers: integer; ch: char);
  25.                 procedure DoActivateDeactivate (activate: boolean);
  26.                 procedure ClickLoop;
  27.                 procedure Click (pt: point; extend: boolean);
  28.                 function WordBreak (text: ptr; pos: integer; forward: boolean): boolean;
  29.             end;
  30.  
  31. implementation
  32.  
  33.     uses
  34.         MyOOMainLoop, BaseGlobals, MyTypes, MyUtils, MySystemGlobals, MyMenus;
  35.  
  36.     var
  37.         teo: TEStaticObject;
  38.         teOriginalClickLoop: procPtr;
  39.  
  40. { DON'T EVEN THINK ABOUT LOOKING AT THIS CODE!!!!! }
  41.  
  42.     procedure CallCL (addr: procPtr);
  43.     inline
  44.         $205F, $4E90;
  45.  
  46.     procedure SetD0to1;
  47.     inline
  48.         $7001;
  49.  
  50.     function GetD2: longInt;
  51.     inline
  52.         $2F42, $0000;
  53.  
  54.     procedure Unlink;
  55.     inline
  56.         $4E5E;
  57.  
  58.     procedure Link;
  59.     inline
  60.         $4E56, $0000;
  61.  
  62. {$PUSH}
  63. {$D-}
  64.   { Turn debug off, lest our qute little SetD0to1 hack gets crunged by TP }
  65.     procedure CallClickLoop;  { There must be a better way to sort out this crap! }
  66.     begin
  67.         Unlink;  { This is a rediculous hack! }
  68.         CallCL(teOriginalClickLoop);
  69.         Link;
  70.         teo.ClickLoop;
  71.         SetD0to1;
  72.     end;
  73.  
  74.     function CallWordBreak (text: ptr; pos: integer): boolean;
  75.         var
  76.             d2: longInt;
  77.     begin
  78.         d2 := GetD2;
  79.         CallWordBreak := teo.WordBreak(text, pos, BAND(d2, $00020000) = 0);
  80.     end;
  81. {$POP}
  82.  
  83.     function FindEOL (te: TEHandle; loc: integer): integer;
  84.     begin
  85.         while (loc < te^^.teLength) and (ptr(longInt(te^^.hText^) + loc)^ <> 13) do
  86.             loc := loc + 1;
  87.         FindEOL := loc;
  88.     end;
  89.  
  90.     procedure TEStaticObject.Click (pt: point; extend: boolean);
  91.         var
  92.             tc, dct: longInt;
  93.             doubleclick, tripleclick: boolean;
  94.             teOriginalWordBreak: procPtr;
  95.             eol: integer;
  96.     begin
  97.         SetPort(window);
  98.         tc := TickCount;
  99.         doubleclick := tc < doubleClickTime;
  100.         tripleclick := tc < tripleClickTime;
  101.         teo := self;
  102.         teOriginalClickLoop := te^^.clikLoop;
  103.         te^^.clikLoop := @CallClickLoop;
  104.         teOriginalWordBreak := te^^.wordBreak;
  105.         if tripleclick then
  106.             SetWordBreak(@CallWordBreak, te);
  107.         if extend and tripleclick then begin{ we must fake text edit into not shrinking the selection somehow }
  108.             eol := FindEOL(te, te^^.selStart);  { if start<=clickloc<=EOL(start)<selEnd }
  109.             if (te^^.selStart <= te^^.clickloc) and (te^^.clickloc <= eol) and (eol < te^^.selEnd) then
  110.                 TESetSelect(te^^.clickloc, te^^.selEnd, te);
  111.         end;
  112.         TEClick(pt, extend, te);
  113.         tc := TickCount;
  114.         dct := GetDblTime;
  115.         doubleClickTime := tc + dct;
  116.         if doubleclick then
  117.             tripleClickTime := tc + dct;
  118.         te^^.clikLoop := teOriginalClickLoop;
  119.         te^^.wordBreak := teOriginalWordBreak;
  120.     end;
  121.  
  122.     procedure TEStaticObject.Create (dlg: dialogPtr; item, width: integer; vscroll, hscroll, hasgrowb, drawgrowb: boolean);
  123.         var
  124.             dr, vr: rect;
  125.             k: integer;
  126.             h: handle;
  127.     begin
  128.         doubleClickTime := -1;
  129.         tripleClickTime := -1;
  130.         SetPort(dlg);
  131.         window := dlg;
  132.         titem := item;
  133.         hasgrow := hasgrowb;
  134.         drawgrow := drawgrowb;
  135.         if vscroll then begin
  136.             SetRect(dr, 0, 0, 16, 100);
  137.             vcontrol := NewControl(window, dr, '', true, 0, 0, 0, scrollBarProc, 0);
  138.         end
  139.         else
  140.             vcontrol := nil;
  141.         if hscroll then begin
  142.             SetRect(dr, 0, 0, 100, 16);
  143.             hcontrol := NewControl(window, dr, '', true, 0, 0, 0, scrollBarProc, 0);
  144.         end
  145.         else
  146.             hcontrol := nil;
  147.         GetDItem(dlg, titem, k, h, dr);
  148.         titemr := dr;
  149.         EraseRect(dr);
  150.         vr := dr;
  151.         dr.right := dr.left + width;
  152.         te := TENew(dr, vr);
  153.         TEAutoView(true, te);
  154.         Resize;
  155.     end;
  156.  
  157.     procedure TEStaticObject.Destroy;
  158.     begin
  159.         TEDispose(te);
  160.         dispose(self);
  161.     end;
  162.  
  163.     procedure AdjustTE (te: TEHandle; hc, vc: integer);
  164. {Scroll the TERec around to match up to the potentially updated scrollbar}
  165. {values. This is really useful when the window resizes such that the}
  166. {scrollbars become inactive and the TERec had been previously scrolled.}
  167.         var
  168.             value: INTEGER;
  169.     begin
  170.         with te^^ do
  171.             TEScroll((viewRect.left - destRect.left) - hc, (viewRect.top - destRect.top) - (vc * lineHeight), te);
  172.     end; {AdjustTE}
  173.  
  174.     function AdjustHV (isVert: BOOLEAN; control: ControlHandle; te: TEHandle; canRedraw: BOOLEAN): integer;
  175. {Calculate the new control maximum value and current value, whether it is the horizontal or}
  176. {vertical scrollbar. The vertical max is calculated by comparing the number of lines to the}
  177. {vertical size of the viewRect. The horizontal max is calculated by comparing the maximum document}
  178. {width to the width of the viewRect. The current values are set by comparing the offset between}
  179. {the view and destination rects. If necessary and we canRedraw, have the control be re-drawn by}
  180. {calling ShowControl.}
  181.         var
  182.             value, lines, max: INTEGER;
  183.             oldValue, oldMax: INTEGER;
  184.             cliprgn: RgnHandle;
  185.             r: rect;
  186.     begin
  187.         oldValue := GetCtlValue(control);
  188.         oldMax := GetCtlMax(control);
  189.         with te^^ do begin
  190.             if isVert then begin
  191.                 lines := nLines;
  192.         {since nLines isn’t right if the last character is a return, check for that case}
  193.                 if (teLength > 0) & (Ptr(ORD(hText^) + teLength - 1)^ = 13) then
  194.                     lines := lines + 1;
  195.                 max := lines - ((viewRect.bottom - viewRect.top) div lineHeight);
  196.             end
  197.             else
  198.                 max := destRect.right - destRect.left - (viewRect.right - viewRect.left);
  199.             if max < 0 then
  200.                 max := 0;            {check for negative values}
  201.             if isVert then
  202.                 value := (viewRect.top - destRect.top) div lineHeight
  203.             else
  204.                 value := viewRect.left - destRect.left;
  205.             if value < 0 then
  206.                 value := 0
  207.             else if value > max then
  208.                 value := max;                    {pin the value to within range}
  209.         end;
  210.         SetPort(te^^.inPort);
  211.         clipRgn := NewRgn;
  212.         GetClip(clipRgn);
  213.         SetRect(r, 0, 0, 0, 0);
  214.         ClipRect(r);
  215.         SetCtlMax(control, max);
  216.         SetClip(clipRgn);
  217.         DisposeRgn(clipRgn);
  218.         SetCtlValue(control, value);
  219.         if canRedraw and ((max <> oldMax) or (value <> oldValue)) then
  220.             ShowControl(control);            {check to see if the control can be re-drawn}
  221.         AdjustHV := value;
  222.     end; {AdjustHV}
  223.  
  224.     procedure TEStaticObject.Adjust;
  225.         var
  226.             hc, vc: integer;
  227.     begin
  228.         vc := AdjustHV(true, vcontrol, te, false);
  229.         hc := AdjustHV(false, hcontrol, te, false);
  230.         AdjustTE(te, hc, vc);
  231.     end; {AdjustScrollValues}
  232.  
  233.     procedure TEStaticObject.Resize;
  234.         const
  235.             invis = 0;
  236.             vis = 255;
  237.             inset = 3;
  238.         var
  239.             dr, vr, r, tr: rect;
  240.             pt: point;
  241.             k: integer;
  242.             h: handle;
  243.             wd, ht: integer;
  244.             hc, vc: integer;
  245.     begin
  246.         SetPort(window);
  247.         EraseRect(titemr);
  248.         GetDItem(window, titem, k, h, tr);
  249.         titemr := tr;
  250.         InvalRect(tr);
  251.         vr := tr;
  252.         InsetRect(vr, inset, inset);
  253.         if hcontrol <> nil then
  254.             vr.bottom := vr.bottom - 15;
  255.         if vcontrol <> nil then
  256.             vr.right := vr.right - 15;
  257.         vr.bottom := vr.top + (vr.bottom - vr.top) div te^^.lineHeight * te^^.lineHeight;
  258.  
  259.         pt := vr.topleft;
  260.         SubPt(te^^.viewRect.topleft, pt);
  261.         OffsetRect(te^^.destRect, pt.h, pt.v);
  262.  
  263.         te^^.viewRect := vr;
  264.  
  265.         if vcontrol <> nil then begin
  266.             vcontrol^^.contrlVis := invis;
  267.             MoveControl(vcontrol, tr.right - 16, tr.top);
  268.             ht := tr.bottom - tr.top;
  269.             if hasgrow then
  270.                 ht := ht - 15;
  271.             SizeControl(vcontrol, 16, ht);
  272.             vc := AdjustHV(true, vcontrol, te, false);
  273.             vcontrol^^.contrlVis := vis;
  274.         end;
  275.         if hcontrol <> nil then begin
  276.             hcontrol^^.contrlVis := invis;
  277.             MoveControl(hcontrol, tr.left, tr.bottom - 16);
  278.             ht := tr.right - tr.left;
  279.             if hasgrow or (vcontrol <> nil) then
  280.                 ht := ht - 15;
  281.             SizeControl(hcontrol, ht, 16);
  282.             hc := AdjustHV(false, hcontrol, te, false);
  283.             hcontrol^^.contrlVis := vis;
  284.         end;
  285.         AdjustTE(te, hc, vc);
  286.     end;
  287.  
  288.     procedure TEStaticObject.Draw;
  289.         var
  290.             r: rect;
  291.             pt: point;
  292.             k: integer;
  293.             h: handle;
  294.     begin
  295.         GetDItem(window, titem, k, h, r);
  296.         EraseRect(r);
  297.         if drawgrow then begin
  298.             DrawGrowIcon(window);
  299.         end;
  300.         if vcontrol <> nil then begin
  301.             Draw1Control(vcontrol);
  302.         end;
  303.         if hcontrol <> nil then begin
  304.             Draw1Control(hcontrol);
  305.         end;
  306.         EraseRect(te^^.viewRect);
  307.         TEUpdate(te^^.viewRect, te);
  308.     end;
  309.  
  310.     procedure TEStaticObject.DoActivateDeactivate (activate: boolean);
  311.     begin
  312.         if drawgrow then
  313.             DrawGrowIcon(window);
  314.         if activate then
  315.             TEActivate(te)
  316.         else
  317.             TEDeactivate(te);
  318.     end;
  319.  
  320. { Common algorithm for pinning the value of a control. It returns the actual amount }
  321. { the value of the control changed. }
  322.     procedure CommonAction (control: ControlHandle; var amount: integer);
  323.         var
  324.             value, max: integer;
  325.     begin
  326.         value := GetCtlValue(control);
  327.         max := GetCtlMax(control);
  328.         amount := value - amount;
  329.         if (amount <= 0) then
  330.             amount := 0
  331.         else if (amount >= max) then
  332.             amount := max;
  333.         SetCtlValue(control, amount);
  334.         amount := value - amount;   { calculate true change }
  335.     end; { CommonAction  }
  336.  
  337.     var
  338.         actionTE: TEHandle;
  339.  
  340. { Determines how much to change the value of the vertical scrollbar by and how }
  341. { much to scroll the TE record.}
  342.     procedure VActionProc (control: ControlHandle; part: integer);
  343.         var
  344.             amount: integer;
  345.             window: WindowPtr;
  346.     begin
  347.         if (part <> 0) then begin
  348.             window := control^^.contrlOwner;
  349.             case part of
  350.                 inUpButton, inDownButton:        { one line  }
  351.                     amount := 1;
  352.                 inPageUp, inPageDown:            { one page  }
  353.                     with actionTE^^, viewRect do
  354.                         amount := (bottom - top) div lineHeight;
  355.             end;
  356.             if ((part = inDownButton) or (part = inPageDown)) then
  357.                 amount := -amount;        { reverse direction for a downer  }
  358.             CommonAction(control, amount);
  359.             if (amount <> 0) then
  360.                 TEScroll(0, amount * actionTE^^.lineHeight, actionTE);
  361.         end;
  362.     end; { VActionProc }
  363.  
  364. { Determines how much to change the value of the horizontal scrollbar by and how }
  365. { much to scroll the TE record. }
  366.     procedure HActionProc (control: ControlHandle; part: integer);
  367.         var
  368.             amount: integer;
  369.             window: WindowPtr;
  370.     begin
  371.         if (part <> 0) then begin
  372.             window := control^^.contrlOwner;
  373.             case part of
  374.                 inUpButton, inDownButton:        { a few pixels }
  375.                     amount := 8;
  376.                 inPageUp, inPageDown:            { a page width }
  377.                     with actionTE^^.viewRect do
  378.                         amount := (right - left);
  379.             end;
  380.             if ((part = inDownButton) or (part = inPageDown)) then
  381.                 amount := -amount;        { reverse direction }
  382.             CommonAction(control, amount);
  383.             if (amount <> 0) then
  384.                 TEScroll(amount, 0, actionTE);
  385.         end;
  386.     end; { HActionProc }
  387.  
  388. { Gets called from CallClickLoop which in turn }
  389. { is called by the TEClick toolbox routine. Saves the window's clip region, }
  390. { sets it to the portRect, adjusts the scrollbar values to match the TE scroll }
  391. { amount, then restores the clip region. }
  392.     procedure TEStaticObject.ClickLoop;
  393.         var
  394.             region: RgnHandle;
  395.             vc, hc: integer;
  396.     begin
  397.         SetPort(window);
  398.         region := NewRgn;
  399.         GetClip(region);                { save the old clip }
  400.         ClipRect(window^.portRect);        { set the new clip }
  401.         vc := AdjustHV(true, vcontrol, te, false);
  402.         hc := AdjustHV(false, hcontrol, te, false);
  403.         SetClip(region);                { restore the old clip }
  404.         DisposeRgn(region);
  405.     end; { PascalClikLoop }
  406.  
  407.     function TEStaticObject.WordBreak (text: ptr; pos: integer; forward: boolean): boolean;
  408.     begin
  409.         if forward then
  410.             WordBreak := (pos > 0) and (ptr(longInt(text) + pos - 1)^ = 13)
  411.         else
  412.             WordBreak := ptr(longInt(text) + pos)^ = 13
  413.     end;
  414.  
  415.     procedure TEStaticObject.DoItemWhere (er: eventRecord; item: integer);
  416.         var
  417.             control: controlHandle;
  418.             value, part: integer;
  419.     begin
  420.         SetPort(window);
  421.         GlobalToLocal(er.where);
  422.         part := FindControl(er.where, window, control);
  423.         if part = 0 then begin
  424.             if PtInRect(er.where, te^^.viewRect) then
  425.                 Click(er.where, BAND(er.modifiers, shiftKey) <> 0)
  426.         end
  427.         else begin
  428.             if part = inThumb then begin
  429.                 value := GetCtlValue(control);
  430.                 part := TrackControl(control, er.where, nil);
  431.                 if part <> 0 then begin
  432.                     value := value - GetCtlValue(control);
  433.                     if value <> 0 then
  434.                         if control = vcontrol then
  435.                             TEScroll(0, value * te^^.lineHeight, te)
  436.                         else
  437.                             TEScroll(value, 0, te);
  438.                 end;
  439.             end
  440.             else begin
  441.                 actionTE := te;
  442.                 if control = vcontrol then
  443.                     value := TrackControl(control, er.where, @VActionProc)
  444.                 else
  445.                     value := TrackControl(control, er.where, @HActionProc);
  446.             end;
  447.         end;
  448.     end;
  449.  
  450.     function TEStaticObject.EditMenuEnabled: boolean;
  451.         var
  452.             i: integer;
  453.     begin
  454.         for i := EMundo to EMselectall do
  455.             if i <> EMundo + 1 then
  456.                 SetEditMenuItem(i);
  457.         EditMenuEnabled := (te^^.selStart < te^^.selEnd) or (te^^.teLength > 0);
  458.     end;
  459.  
  460.     procedure TEStaticObject.SetEditMenuItem (item: integer);
  461.     begin
  462.         case item of
  463.             EMundo, EMcut, EMpaste, EMclear:  { Can't undo, cut, copy, paste in a static edit thingy }
  464.                 SetIDItemEnable(M_Edit, item, false);
  465.             EMcopy: 
  466.                 SetIDItemEnable(M_Edit, item, te^^.selStart < te^^.selEnd);  { Can copy iff there is a selection }
  467.             EMselectall: 
  468.                 SetIDItemEnable(M_Edit, item, te^^.teLength > 0);  { Can select all iff there is something to select }
  469.             otherwise
  470.         end;
  471.     end;
  472.  
  473.     procedure TEStaticObject.DoEditMenu (item: integer);
  474.         var
  475.             oe: OSErr;
  476.             loe: longInt;
  477.     begin
  478.         case item of
  479.             EMcopy:  begin
  480.                 TECopy(te);
  481.                 loe := ZeroScrap;
  482.                 oe := TEToScrap;
  483.             end;
  484.             EMselectall:  begin
  485.                 SetPort(window);
  486.                 TESetSelect(0, maxLongInt, te);
  487.             end;
  488.             otherwise
  489.         end;
  490.     end;
  491.  
  492.     procedure TEStaticObject.DoIdle;
  493.     begin
  494.         TEIdle(te);
  495.     end;
  496.  
  497.     procedure TEStaticObject.DoKey (modifiers: integer; ch: char);
  498.     begin
  499.         if BAND(modifiers, cmdKey) = 0 then
  500.             TEKey(ch, te);
  501.         Adjust;
  502.     end;
  503.  
  504. end.